do not call _gtk_text_btree_get_iter_at_line() and
authorYevgen Muntyan <muntyan@tamu.edu>
Thu, 15 Nov 2007 16:24:42 +0000 (16:24 +0000)
committerYevgen Muntyan <muntyan@src.gnome.org>
Thu, 15 Nov 2007 16:24:42 +0000 (16:24 +0000)
2007-11-15  Yevgen Muntyan  <muntyan@tamu.edu>

* gtk/gtktextlayout.c: (gtk_text_layout_get_line_display),
(get_style): do not call _gtk_text_btree_get_iter_at_line() and
_gtk_text_btree_get_tags() for every segment, instead call them
once and then collect the tags while iterating over the segments.
(get_tags_array_at_iter), (tags_array_toggle_tag): new functions
for tags array handling.

svn path=/trunk/; revision=18994

ChangeLog
gtk/gtktextlayout.c

index e766d4cdb89049b907a6253974d9d071cb71ea5d..478650737d582863347cc0ab8f53c95b33b849fd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2007-11-15  Yevgen Muntyan  <muntyan@tamu.edu>
+
+       * gtk/gtktextlayout.c: (gtk_text_layout_get_line_display),
+       (get_style): do not call _gtk_text_btree_get_iter_at_line() and
+       _gtk_text_btree_get_tags() for every segment, instead call them
+       once and then collect the tags while iterating over the segments.
+       (get_tags_array_at_iter), (tags_array_toggle_tag): new functions
+       for tags array handling.
+
 2007-11-14  Michael Natterer  <mitch@imendio.com>
 
        * gtk/gtkmenu.c (gtk_menu_popup): remove recently added
index 8faefef552661ee123d098539e71e41aaefa3106..0b1b708f8c23090b0b579b356c965d5e445c2d58 100644 (file)
@@ -1166,10 +1166,8 @@ gtk_text_layout_real_wrap (GtkTextLayout   *layout,
    release_style () to free it. */
 static GtkTextAttributes*
 get_style (GtkTextLayout *layout,
-           const GtkTextIter *iter)
+          GPtrArray     *tags)
 {
-  GtkTextTag** tags;
-  gint tag_count = 0;
   GtkTextAttributes *style;
 
   /* If we have the one-style cache, then it means
@@ -1184,11 +1182,8 @@ get_style (GtkTextLayout *layout,
 
   g_assert (layout->one_style_cache == NULL);
 
-  /* Get the tags at this spot */
-  tags = _gtk_text_btree_get_tags (iter, &tag_count);
-
   /* No tags, use default style */
-  if (tags == NULL || tag_count == 0)
+  if (tags == NULL || tags->len == 0)
     {
       /* One ref for the return value, one ref for the
          layout->one_style_cache reference */
@@ -1196,24 +1191,17 @@ get_style (GtkTextLayout *layout,
       gtk_text_attributes_ref (layout->default_style);
       layout->one_style_cache = layout->default_style;
 
-      g_free (tags);
-
       return layout->default_style;
     }
 
-  /* Sort tags in ascending order of priority */
-  _gtk_text_tag_array_sort (tags, tag_count);
-
   style = gtk_text_attributes_new ();
 
   gtk_text_attributes_copy_values (layout->default_style,
                                    style);
 
   _gtk_text_attributes_fill_from_tags (style,
-                                       tags,
-                                       tag_count);
-
-  g_free (tags);
+                                       (GtkTextTag**) tags->pdata,
+                                       tags->len);
 
   g_assert (style->refcount == 1);
 
@@ -2071,6 +2059,60 @@ update_text_display_cursors (GtkTextLayout      *layout,
   g_slist_free (cursor_segs);
 }
 
+/* Same as _gtk_text_btree_get_tags(), except it returns GPtrArray,
+ * to be used in gtk_text_layout_get_line_display(). */
+static GPtrArray *
+get_tags_array_at_iter (GtkTextIter *iter)
+{
+  GtkTextTag **tags;
+  GPtrArray *array = NULL;
+  gint n_tags;
+
+  tags = _gtk_text_btree_get_tags (iter, &n_tags);
+
+  if (n_tags > 0)
+    {
+      /* Sort tags in ascending order of priority */
+      _gtk_text_tag_array_sort (tags, n_tags);
+      array = g_ptr_array_sized_new (n_tags);
+      g_ptr_array_set_size (array, n_tags);
+      memcpy (array->pdata, tags, n_tags * sizeof (GtkTextTag*));
+    }
+
+  g_free (tags);
+  return array;
+}
+
+/* Add the tag to the array if it's not there already, and remove
+ * it otherwise. It keeps the array sorted by tags priority. */
+static GPtrArray *
+tags_array_toggle_tag (GPtrArray  *array,
+                      GtkTextTag *tag)
+{
+  gint pos;
+  GtkTextTag **tags;
+
+  if (array == NULL)
+    array = g_ptr_array_new ();
+
+  tags = (GtkTextTag**) array->pdata;
+
+  for (pos = 0; pos < array->len && tags[pos]->priority < tag->priority; pos++) ;
+
+  if (pos < array->len && tags[pos] == tag)
+    g_ptr_array_remove_index (array, pos);
+  else
+    {
+      g_ptr_array_set_size (array, array->len + 1);
+      if (pos < array->len - 1)
+       memmove (array->pdata + pos + 1, array->pdata + pos,
+                (array->len - pos - 1) * sizeof (GtkTextTag*));
+      array->pdata[pos] = tag;
+    }
+
+  return array;
+}
+
 GtkTextLineDisplay *
 gtk_text_layout_get_line_display (GtkTextLayout *layout,
                                   GtkTextLine   *line,
@@ -2091,6 +2133,8 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
   GSList *tmp_list1, *tmp_list2;
   gboolean saw_widget = FALSE;
   PangoDirection base_dir;
+  GPtrArray *tags;
+  gboolean initial_toggle_segments;
   
   g_return_val_if_fail (line != NULL, NULL);
 
@@ -2155,10 +2199,12 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
 
   attrs = pango_attr_list_new ();
 
-  /* Iterate over segments, creating display chunks for them. */
+  /* Iterate over segments, creating display chunks for them, and updating the tags array. */
   layout_byte_offset = 0; /* current length of layout text (includes preedit, does not include invisible text) */
   buffer_byte_offset = 0; /* position in the buffer line */
   seg = _gtk_text_iter_get_any_segment (&iter);
+  tags = get_tags_array_at_iter (&iter);
+  initial_toggle_segments = TRUE;
   while (seg != NULL)
     {
       /* Displayable segments */
@@ -2166,10 +2212,8 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
           seg->type == &gtk_text_pixbuf_type ||
           seg->type == &gtk_text_child_type)
         {
-          _gtk_text_btree_get_iter_at_line (_gtk_text_buffer_get_btree (layout->buffer),
-                                            &iter, line,
-                                            buffer_byte_offset);
-          style = get_style (layout, &iter);
+          style = get_style (layout, tags);
+         initial_toggle_segments = FALSE;
 
           /* We have to delay setting the paragraph values until we
            * hit the first pixbuf or text segment because toggles at
@@ -2298,6 +2342,10 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
           /* Style may have changed, drop our
              current cached style */
           invalidate_cached_style (layout);
+         /* Add the tag only after we have seen some non-toggle non-mark segment,
+          * otherwise the tag is already accounted for by _gtk_text_btree_get_tags(). */
+         if (!initial_toggle_segments)
+           tags = tags_array_toggle_tag (tags, seg->body.toggle.info->tag);
         }
 
       /* Marks */
@@ -2318,7 +2366,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
                  text_allocated += layout->preedit_len;
                  text = g_realloc (text, text_allocated);
 
-                 style = get_style (layout, &iter);
+                 style = get_style (layout, tags);
                  add_preedit_attrs (layout, style, attrs, layout_byte_offset, size_only);
                  release_style (layout, style);
                   
@@ -2349,7 +2397,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
   
   if (!para_values_set)
     {
-      style = get_style (layout, &iter);
+      style = get_style (layout, tags);
       set_para_values (layout, base_dir, style, display);
       release_style (layout, style);
     }
@@ -2426,6 +2474,8 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
 
   g_free (text);
   pango_attr_list_unref (attrs);
+  if (tags != NULL)
+    g_ptr_array_free (tags, TRUE);
 
   layout->one_display_cache = display;